package codechicken.wirelessredstone.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeMap;

import net.minecraft.src.ModLoader;

public class ConfigFile
{
	public static class TagOrderComparator implements Comparator<ConfigTag>
	{
		public int compare(ConfigTag o1, ConfigTag o2)
		{
			if(o1.position == o2.position)
			{
				if(o1.brace == o2.brace)
				{
					return o1.name.compareTo(o2.name);
				}
				else
				{
					return o1.brace ? 1 : -1;//braced one goes after
				}
			}
			else
			{
				return Integer.valueOf(o1.position).compareTo(o2.position);
			}
		}
		
	}
	
	public ConfigFile(File file)
	{
		if(!file.exists())
		{
			try
			{
				file.createNewFile();
			}
			catch(IOException e)
			{
				ModLoader.ThrowException("Config File Init", e);
			}
		}
		this.file = file;
		maintags = new TreeMap<String, ConfigTag>();
		loadConfig();
	}
	
	private void loadConfig()
	{
		loading = true;
		EOF = false;
		FileInputStream fin;
		try
		{
			fin = new FileInputStream(file);
		}
		catch(FileNotFoundException e)
		{
			e.printStackTrace();
			return;
		}
		
		String comment = "";
		String bracequalifier="";
		boolean readingheader = true;
		while(!EOF)
		{
			boolean headerline = false;
			String line = readLine(fin);
			if(line.startsWith("#"))
			{
				if(readingheader)
				{
					if(comment == null || comment.equals(""))
					{
						this.comment = line.substring(1);
					}
					else
					{
						this.comment = this.comment+":"+line.substring(1);
					}
					headerline = true;
				}
				else
				{
					if(comment == null || comment.equals(""))
					{
						comment = line.substring(1);
					}
					else
					{
						comment = comment+":"+line.substring(1);
					}
				}
			}
			else if(line.contains("="))
			{
				String qualifiedname = line.substring(0, line.indexOf("="));
				getTag(qualifiedname)
				.setComment(comment)
				.setValue(line.substring(line.indexOf("=")+1));
				comment = "";
				bracequalifier = "";
			}
			else if(line.equals("{"))
			{
				getTag(bracequalifier).setComment(comment).useBraces().loadChildren(fin);
				comment = "";
				bracequalifier = "";
			}
			else if(line.equals(""))
			{
				comment = "";
				bracequalifier = "";
			}
			else
			{
				bracequalifier = line;
			}
			if(!headerline)
			{
				readingheader = false;
			}
		}
		
		loading = false;
	}
	
	public static String readLine(FileInputStream fin)
	{
		byte[] data = new byte[1024];
		int numbytes = 0;
		int lastbyte = 0;
		while(true)//0xD,0xA
		{
			try
			{
				int databyte = fin.read();
				if(databyte == -1)
				{
					EOF = true;
					return formatLine(new String(data, 0, numbytes, "US-ASCII"));
				}
				else if(lastbyte == 0xD && databyte == 0xA)
				{
					return formatLine(new String(data, 0, numbytes-1, "US-ASCII"));
				}
				lastbyte = databyte;
				data[numbytes] = (byte) databyte;
				numbytes++;
			}
			catch(IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	public static String formatLine(String line)
	{
		line = line.replace("\t", "");
		if(line.startsWith("#"))
		{
			return line;
		}
		else if(line.contains("="))
		{
			line = line.substring(0, line.indexOf("=")).replace(" ", "")+line.substring(line.indexOf("="));
			return line;
		}
		else
		{
			line = line.replace(" ", "");
			return line;
		}
	}
	
	public static void writeLine(FileOutputStream fout, String line, int tabs)
	{
		try
		{
			for(int i = 0; i < tabs; i++)
			{
				fout.write((byte)0x9);
			}
			byte[] data = line.getBytes("US-ASCII");
			fout.write(data);
			fout.write(lineend);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}		
	}
	
	public ConfigTag getTag(String tagname)
	{
		int dotpos = tagname.indexOf(".");
		String basetagname = dotpos == -1 ? tagname : tagname.substring(0, dotpos);
		ConfigTag basetag = maintags.get(basetagname);
		if(basetag == null)
		{
			basetag = new ConfigTag(this, basetagname);
			saveConfig();
		}
		if(dotpos == -1)
		{
			return basetag;
		}
		else
		{
			return basetag.getTag(tagname.substring(dotpos+1));
		}
	}
	
	public void saveConfig()
	{
		if(loading)
		{
			return;
		}
		
		FileOutputStream fout;
		try
		{
			fout = new FileOutputStream(file);
		}
		catch(FileNotFoundException e)
		{
			e.printStackTrace();
			return;
		}
		
		if(comment != null && !comment.equals(""))
		{
			String[] comments = comment.split(":");
			for(int i = 0; i < comments.length; i++)
			{
				writeLine(fout, "#"+comments[i], 0);
			}
		}
		saveTagTree(fout, maintags, 0, "");
	}
	
	public ConfigFile setComment(String header)
	{
		comment = header;
		saveConfig();
		return this;
	}
	
	public static void saveTagTree(FileOutputStream fout, TreeMap<String, ConfigTag> tagtree, int braces, String bracequalifier)
	{
		ArrayList<ConfigTag> taglist = new ArrayList<ConfigTag>(tagtree.size());
		for(Iterator<String> iterator = tagtree.keySet().iterator(); iterator.hasNext();)
		{
			ConfigTag tag = tagtree.get(iterator.next());
			taglist.add(tag);
		}
		
		Collections.sort(taglist, new TagOrderComparator());

		for(Iterator<ConfigTag> iterator = taglist.iterator(); iterator.hasNext();)
		{
			iterator.next().save(fout, braces, bracequalifier);
		}		
	}
	
	public File file;
	public TreeMap<String, ConfigTag> maintags;
	public String comment;
	public static boolean EOF;
	public static boolean loading;
	
	public static final byte[] lineend = new byte[]{0xD, 0xA};
}
